<?php
declare(strict_types=1);

namespace App\Service;

use App\Constants\SettleAccessType;
use App\Model\Dao\ChannelInfoDao;
use App\Model\Dao\TradeOrderDetailDao;
use App\Model\Dao\TradeOrderLogDao;
use App\Model\Enum\OrderHandleStatusEnum;
use App\Model\Enum\OrderTransTypeEnum;
use App\Model\Enum\StatusEnum;
use App\Utils\CustomUtils;
use Hyperf\Di\Annotation\Inject;
use App\Model\Dao\TradeOrderRefundDao;
use App\Exception\XZXValidationException;
use App\Constants\XZXResponseCode;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Coroutine;
use App\Utils\DateUtils;
use App\Constants\StrStatus;
use App\Service\EmailService;


class TradeOrderRefundService
{
    /**
     * @Inject()
     * @var TradeOrderRefundDao
     */
    private $TradeOrderRefundDao;

    /**
     * @Inject()
     * @var TradeOrderDetailDao
     */
    private $TradeOrderDetailDao;

    /**
     * @Inject()
     * @var TradeOrderLogDao
     */
    private $TradeOrderLogDao;

    /**
     * @Inject()
     * @var ChannelInfoDao
     */
    private $ChannelInfoDao;

    /**
     * @Inject()
     * @var EmailService
     */
    private $EmailService;

    /**
     * @Inject()
     * @var SettleService
     */
    private $SettleService;

    public function get($param)
    {
        $result = $this->TradeOrderRefundDao->get($param['id']);
        if (!$result) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DATA_NOT_FOUND));
        }
        (isset($result['createTime']) && !empty($result['createTime'])) && $result['createTime'] = DateUtils::getDateTime($result['createTime']);
        $result['strHandleStatus'] = OrderHandleStatusEnum::getLabel($result['handleStatus']);

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE,XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE),$result);
    }

    public function del($param)
    {
        $result = $this->TradeOrderRefundDao->get($param['id']);
        if (!$result) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DATA_NOT_FOUND));
        }

        try {
            $result = $this->TradeOrderRefundDao->del($param['id'],false);
        } catch (\Throwable $th) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DEL_FAIL));
        }
        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE,XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE),CustomUtils::xzxEmptyObject());
    }

    public function add($param)
    {
        $tradeOrder = $this->TradeOrderDetailDao->getWhere([
            "id"    => $param['orderId'],
            "mchId" => $param['mchId'],
        ]);
        if (!$tradeOrder) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DATA_NOT_FOUND));
        }

        if ($tradeOrder['isSettle'] != 2) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::NO_SETTLEMENT));
        }

        // 已经发起拒付不能操作
        if ($tradeOrder['isDis'] == 1 || $tradeOrder['isDis'] == 2) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::REFUSING_ORDER));
        }

        // 已经拒付
        if ($tradeOrder['isDis'] == 4) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::REFUSED_ORDER));
        }

        // 已经冻结不能操作
        if ($tradeOrder['isFrozen'] == 1 || $tradeOrder['isFrozen'] == 2) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::FROZENING_ORDER));
        }

        // 已经冻结不能操作
        if ($tradeOrder['isFrozen'] == 4) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::FROZENED_ORDER));
        }

        $isRefund = $this->TradeOrderRefundDao->getByTradeNo($param['tradeNo']);

        if ($tradeOrder['isRefund'] == 1 || $tradeOrder['isRefund'] == 2 || (!empty($isRefund) && $isRefund['handleStatus'] == 0)  || (!empty($isRefund) && $isRefund['handleStatus'] == 1)) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::REFUNDING_ORDER));
        }

        // 已经退款不能操作
        if ($tradeOrder['isRefund'] == 4) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::REFUNDED_ORDER));
        }

        // 找对应的通道是否有退款api
        $channel = $this->ChannelInfoDao->get($tradeOrder['channelId']);

        $data = [
            "id"                  => CustomUtils::createUUID(),
            "mchId"               => $tradeOrder['mchId'],
            "mchNo"               => $tradeOrder['mchNo'],
            "tradeNo"             => $tradeOrder['tradeNo'],
            "orderId"             => $tradeOrder['id'],
            "tradeNewNo"          => CustomUtils::createTradeNo('refund'),
            "transAmount"         => $tradeOrder['mchTransAmount'],
            "transCurrency"       => $tradeOrder['mchTransCurrency'],
            "transSettleCurrency" => $tradeOrder['settleCurrency'],
            "transSettleAmount"   => $tradeOrder['settleAmount'],
            "handleStatus"        => 0,
            'refundByApi'         => $channel['canRefund'],
            "transReason"         => $param['transReason'],
            "createBy"            => $param['createBy'],
            "createTime"          => time(),
        ];

        try {
            $this->TradeOrderRefundDao->insert($data);

            $this->TradeOrderDetailDao->update($data['orderId'], [
                'isRefund'  => 1,
            ]);
        } catch (\Throwable $th) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::ADD_FAIL));
        }

        // 写队列，退款结算
        $this->SettleService->addMq($tradeOrder['mchId'], [
            "accessType" => SettleAccessType::ACCESS_TYPE_TRADE_ORDER_REFUND,
            "refundId" => $data['id'],
            "handleStatus" => 0
        ]);

        // todo 发送邮件
        $sendMailParam = array(
            'type'    => 15,
            'email'   => env('NOTIFY_EMAIL'),
            "tradeNo" => $tradeOrder['tradeNo'],
        );
        CustomUtils::xzxDebug($sendMailParam);
        $this->EmailService->addMq($sendMailParam);

        $this->addOrderLog([$data]);

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE,XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE),CustomUtils::xzxEmptyObject());
    }

    public function edit($param)
    {
        $info = $this->TradeOrderRefundDao->get($param['id']);
        if (!$info) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::DATA_NOT_FOUND));
        }

        $id = $param['id'];
        $data = array();

        foreach($param as $k => $v){
            if($k == "id"){
                continue;
            }
            if(isset($v)){
                $data[$k] = $v;
            }
        }
        CustomUtils::xzxDebug($data);

        try {
            $this->TradeOrderRefundDao->update($id, $data);
        } catch (\Throwable $th) {
            throw new XZXValidationException(XZXResponseCode::getMessage(XZXResponseCode::EDIT_FAIL));
        }
        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE,XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE),CustomUtils::xzxEmptyObject());
    }

    public function list(array $param)
    {

        $limit = $param['limit'];
        $page = $param['page'];

        $total = $this->TradeOrderRefundDao->getCount($param);
        $list = $this->TradeOrderRefundDao->getList($param, $page, $limit);

        foreach ($list as $k => $v) {
            (isset($v['createTime']) && !empty($v['createTime'])) && $v['createTime'] = DateUtils::getDateTime($v['createTime']);
            $v['strHandleStatus'] = OrderHandleStatusEnum::getLabel($v['handleStatus']);
            $list[$k] = $v;
        }

        $data = array(
            'total' => $total,
            'list' => $list
        );

        return CustomUtils::xeServiceReturnData(XZXResponseCode::SUCCESS_CODE,XZXResponseCode::getMessage(XZXResponseCode::SUCCESS_CODE),$data);
    }

    /**
     * 写入交易变更日志
     *
     * @param $orderList
     */
    public function addOrderLog ($orderList) {
        $logList = [];

        foreach ($orderList as $order) {
            $log = [
                'id'            => CustomUtils::createUUID(),
                'transId'       => $order['id'],
                'mchId'         => $order['mchId'],
                'mchNo'         => $order['mchNo'],
                'orderId'       => $order['orderId'],
                'tradeNo'       => $order['tradeNo'],
                'tradeNewNo'    => $order['tradeNewNo'],
                'transType'     => OrderTransTypeEnum::REFUND,
                'transCurrency' => $order['transCurrency'],
                'transAmount'   => $order['transAmount'],
                'transReason'   => $order['transReason'],
                'handleStatus'  => $order['handleStatus'],
                'status'        => StatusEnum::ON,
                'createTime'    => time(),
                'createBy'      => $order['createBy'],
            ];

            array_push($logList, $log);
        }

        $this->TradeOrderLogDao->insert($logList);
    }
}
